package com.chap6;

import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 * <code>ReentrantLockDemo5</code>
 * </p>
 *
 * @author junbao3
 * TODO
 * @date 2023-03-17 8:54
 * Copyright (C) 2021 IFlyTek. All rights reserved.
 */
public class ReentrantLockDemo5 {
    public static void main(String[] args) {
        Queue queue = new Queue(5);
        new Thread(new Producer(queue),"生产者1").start();
        new Thread(new Producer(queue),"生产者2").start();
        new Thread(new Consumer(queue),"消费者1").start();
    }
}



class Queue{
    private Object[] items;
    int size = 0;
    int takeIndex;
    int putIndex;
    private ReentrantLock lock;
    public Condition notEmpty;//消费者线程阻塞唤醒条件，队列为空阻塞，生产者生产完唤醒
    public Condition notFull;//生产者线程阻塞唤醒条件，队列满了阻塞，消费者消费完唤醒

    public Queue(int capactiy) {
        this.items = new Object[capactiy];
        lock = new ReentrantLock();
        notEmpty = lock.newCondition();
        notFull = lock.newCondition();
    }


    //生产者往队列塞东西
    public void put(Object value) throws InterruptedException {
//        lock.lock();
        try {
            while (size==items.length){
                notFull.await();
            }
            items[putIndex] = value;
            if (++putIndex == items.length){
                putIndex=0;
            }
            size++;
            notEmpty.signal();
        }finally {
//            lock.unlock();
            System.out.println(Thread.currentThread().getName()+"生产："+value);
        }
    }

    //生产者往队列塞东西
    public Object take() throws InterruptedException {
        lock.lock();
        try {
            while (size==0){
                notEmpty.await();
            }
            Object value = items[takeIndex];
            if (++takeIndex == items.length){
                takeIndex=0;
            }
            size--;
            notFull.signal();
            return value;
        }finally {
            lock.unlock();
        }
    }
}

class Producer implements Runnable{
    private Queue queue;

    public Producer(Queue queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            while (true){
                Thread.sleep(1000);//1秒生产一次
                queue.put(new Random().nextInt(1000));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

class Consumer implements Runnable{
    private Queue queue;

    public Consumer(Queue queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            while (true){
                Thread.sleep(2000);//2秒消费一次
                System.out.println(Thread.currentThread().getName()+"消费："+queue.take());
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
